---
title: 音声エージェントの構築
description: Learn how to build voice agents using the OpenAI Agents SDK, what features are available, how to architecture your application, and more.
---

import { Steps, Aside, Code } from '@astrojs/starlight/components';
import createAgentExample from '../../../../../../../examples/docs/voice-agents/createAgent.ts?raw';
import multiAgentsExample from '../../../../../../../examples/docs/voice-agents/multiAgents.ts?raw';
import createSessionExample from '../../../../../../../examples/docs/voice-agents/createSession.ts?raw';
import configureSessionExample from '../../../../../../../examples/docs/voice-agents/configureSession.ts?raw';
import handleAudioExample from '../../../../../../../examples/docs/voice-agents/handleAudio.ts?raw';
import defineToolExample from '../../../../../../../examples/docs/voice-agents/defineTool.ts?raw';
import toolApprovalEventExample from '../../../../../../../examples/docs/voice-agents/toolApprovalEvent.ts?raw';
import guardrailsExample from '../../../../../../../examples/docs/voice-agents/guardrails.ts?raw';
import guardrailSettingsExample from '../../../../../../../examples/docs/voice-agents/guardrailSettings.ts?raw';
import audioInterruptedExample from '../../../../../../../examples/docs/voice-agents/audioInterrupted.ts?raw';
import sessionInterruptExample from '../../../../../../../examples/docs/voice-agents/sessionInterrupt.ts?raw';
import sessionHistoryExample from '../../../../../../../examples/docs/voice-agents/sessionHistory.ts?raw';
import historyUpdatedExample from '../../../../../../../examples/docs/voice-agents/historyUpdated.ts?raw';
import updateHistoryExample from '../../../../../../../examples/docs/voice-agents/updateHistory.ts?raw';
import customWebRTCTransportExample from '../../../../../../../examples/docs/voice-agents/customWebRTCTransport.ts?raw';
import websocketSessionExample from '../../../../../../../examples/docs/voice-agents/websocketSession.ts?raw';
import transportEventsExample from '../../../../../../../examples/docs/voice-agents/transportEvents.ts?raw';
import thinClientExample from '../../../../../../../examples/docs/voice-agents/thinClient.ts?raw';
import toolHistoryExample from '../../../../../../../examples/docs/voice-agents/toolHistory.ts?raw';
import sendMessageExample from '../../../../../../../examples/docs/voice-agents/sendMessage.ts?raw';
import serverAgentExample from '../../../../../../../examples/docs/voice-agents/serverAgent.ts?raw';
import delegationAgentExample from '../../../../../../../examples/docs/voice-agents/delegationAgent.ts?raw';
import turnDetectionExample from '../../../../../../../examples/docs/voice-agents/turnDetection.ts?raw';

## 音声の取り扱い

`OpenAIRealtimeWebRTC` のような一部のトランスポートレイヤーは、音声の入出力を自動で処理します。`OpenAIRealtimeWebSocket` のような他のトランスポートメカニズムでは、セッションの音声を自分で処理する必要があります:

<Code lang="typescript" code={handleAudioExample} />

## セッションの設定

[`RealtimeSession`](/openai-agents-js/openai/agents-realtime/classes/realtimesession/) のコンストラクタ、または `connect(...)` を呼び出す際に追加オプションを渡して、セッションを設定できます。

<Code lang="typescript" code={configureSessionExample} />

これらのトランスポートレイヤーでは、[session](https://platform.openai.com/docs/api-reference/realtime-client-events/session/update) と一致する任意のパラメーターを渡せます。

[RealtimeSessionConfig](/openai-agents-js/openai/agents-realtime/type-aliases/realtimesessionconfig/) にまだ存在しない新しいパラメーターについては、`providerData` を使用できます。`providerData` に渡したものは `session` オブジェクトの一部としてそのまま渡されます。

## ハンドオフ

通常のエージェントと同様に、ハンドオフを使ってエージェントを複数に分割し、それらをオーケストレーションすることで、エージェントのパフォーマンスを向上させ、問題のスコープをより適切に絞ることができます。

<Code lang="typescript" code={multiAgentsExample} />

通常のエージェントと異なり、リアルタイムエージェントのハンドオフは少し挙動が異なります。ハンドオフが行われると、進行中のセッションは新しいエージェント設定で更新されます。このため、エージェントは進行中の会話履歴に自動でアクセスでき、現在は入力フィルターが適用されません。

また、ハンドオフの一部として `voice` や `model` を変更することはできません。接続できるのは他のリアルタイムエージェントのみです。異なるモデル、例えば `o4-mini` のような推論モデルを使用する必要がある場合は、[delegation through tools](#delegation-through-tools) を使用できます。

## ツール

通常のエージェントと同様に、リアルタイムエージェントはツールを呼び出してアクションを実行できます。通常のエージェントで使用するのと同じ `tool()` 関数でツールを定義できます。

<Code lang="typescript" code={defineToolExample} />

リアルタイムエージェントで使用できるのは 関数ツール のみで、これらのツールはリアルタイムセッションと同じ場所で実行されます。つまり、リアルタイムセッションをブラウザで実行している場合、ツールもブラウザで実行されます。よりセンシティブな処理が必要な場合は、ツール内からバックエンド サーバーへの HTTP リクエストを行ってください。

ツールの実行中、エージェントはユーザーからの新しいリクエストを処理できません。体験を改善する 1 つの方法は、ツールを実行しようとしていることをエージェントにアナウンスさせたり、ツールの実行時間を稼ぐために特定のフレーズを話させるよう指示することです。

### 会話履歴へのアクセス

エージェントが特定のツールを呼び出した際の引数に加えて、リアルタイムセッションで追跡されている現在の会話履歴のスナップショットにもアクセスできます。これは、会話の現在の状態に基づいてより複雑なアクションを行う必要がある場合や、[tools for delegation](#delegation-through-tools) を使用する予定がある場合に便利です。

<Code lang="typescript" code={toolHistoryExample} />

<Aside type="note">
  渡される履歴は、ツール呼び出し時点での履歴のスナップショットです。
  ユーザーが最後に発話した内容の文字起こしがまだ利用できない場合があります。
</Aside>

### ツール実行前の承認

ツールを `needsApproval: true` で定義すると、エージェントはツールを実行する前に `tool_approval_requested` イベントを発行します。

このイベントをリッスンして、ユーザーがツール呼び出しを承認または拒否できる UI を表示できます。

<Code lang="typescript" code={toolApprovalEventExample} />

<Aside type="note">
  音声エージェントがツール呼び出しの承認待ちの間、エージェントはユーザーからの新しいリクエストを処理できません。
</Aside>

## ガードレール

ガードレールは、エージェントの発話が一連のルールに違反していないかを監視し、違反していれば直ちに応答を打ち切る方法を提供します。これらのガードレールチェックはエージェント応答の文字起こしに基づいて実行されるため、モデルのテキスト出力を有効にしておく必要があります（デフォルトで有効）。

提供したガードレールは、モデル応答の返却中に非同期で実行され、あらかじめ定義した分類のトリガー（例: 特定の禁止語を発話した）に基づいて応答を打ち切ることができます。

ガードレールが作動すると、セッションは `guardrail_tripped` イベントを発行します。イベントは、ガードレールを作動させた `itemId` を含む `details` オブジェクトも提供します。

<Code lang="typescript" code={guardrailsExample} />

デフォルトでは、ガードレールは 100 文字ごと、または応答テキストの末尾で実行されます。音声での読み上げは通常より時間がかかるため、多くの場合、ユーザーが聞く前にガードレールが違反を検知できます。

この挙動を変更したい場合は、`outputGuardrailSettings` オブジェクトをセッションに渡してください。

<Code lang="typescript" code={guardrailSettingsExample} />

## ターン検出 / 音声活動検出

リアルタイムセッションは、ユーザーが話しているタイミングを自動で検出し、組み込みの [voice activity detection modes of the Realtime API](https://platform.openai.com/docs/guides/realtime-vad) を使って新しいターンをトリガーします。

`turnDetection` オブジェクトをセッションに渡して、音声活動検出のモードを変更できます。

<Code lang="typescript" code={turnDetectionExample} />

ターン検出の設定を調整することで、不要な割り込みの抑制や無音の扱いを調整できます。各種設定の詳細は [Realtime API documentation for more details on the different settings](https://platform.openai.com/docs/guides/realtime-vad) を参照してください。

## 割り込み

組み込みの音声活動検出を使用している場合、エージェントの発話に被せて話すと、エージェントは発話内容に基づいて自動的にコンテキストを検出・更新します。同時に `audio_interrupted` イベントを発行します。これはすべての音声再生を即時に停止するために使用できます（WebSocket 接続の場合のみ適用）。

<Code lang="typescript" code={audioInterruptedExample} />

UI に「停止」ボタンを用意するなど、手動で割り込みを行いたい場合は、`interrupt()` を手動で呼び出せます:

<Code lang="typescript" code={sessionInterruptExample} />

いずれの場合も、リアルタイムセッションはエージェントの生成の割り込み、ユーザーに対して発話した内容の切り詰め、履歴の更新を処理します。

エージェントに接続するのに WebRTC を使用している場合は、音声出力もクリアされます。WebSocket を使用している場合は、キューに入っている音声再生を停止する処理を自分で行う必要があります。

## テキスト入力

エージェントにテキスト入力を送信したい場合は、`RealtimeSession` の `sendMessage` メソッドを使用します。

ユーザーがエージェントと複数のモダリティでやり取りできるようにしたい場合や、会話に追加のコンテキストを提供したい場合に便利です。

<Code lang="typescript" code={sendMessageExample} />

## 会話履歴の管理

`RealtimeSession` は `history` プロパティ内で会話履歴を自動的に管理します:

これを使って顧客向けに履歴をレンダリングしたり、追加の処理を行ったりできます。会話の進行中に履歴は継続的に変化するため、`history_updated` イベントをリッスンできます。

履歴を変更したい場合（メッセージを完全に削除する、文字起こしを更新する など）は、`updateHistory` メソッドを使用します。

<Code lang="typescript" code={updateHistoryExample} />

### 制限事項

1. 現時点では、後から 関数ツール の呼び出し内容を更新・変更することはできません
2. 履歴でのテキスト出力には、文字起こしとテキストモダリティの有効化が必要です
3. 割り込みによって切り詰められた応答には文字起こしがありません

## Delegation through tools

![Delegation through tools](https://cdn.openai.com/API/docs/diagram-speech-to-speech-agent-tools.png)

会話履歴とツール呼び出しを組み合わせることで、より複雑な処理を他のバックエンド エージェントに委譲し、その結果をユーザーへ返すことができます。

<Code lang="typescript" code={delegationAgentExample} />

以下のコードは サーバー 上で実行されます。この例では Next.js の server actions を通じて実行します。

<Code lang="typescript" code={serverAgentExample} />
